let count = 0
document.getElementById('root').innerText = count
function userAction(e) {
    console.group('事件')
    console.log(e)
    console.log(this)
    console.groupEnd('事件')
    document.getElementById('root').innerText = ++count
}
// 下面的函数体如果是网络请求就会有卡顿出现，为了解决这个问题就需要用到防抖或节流。
// document.onmousemove = userAction

// 防抖：你尽管触发事件，我一定会在触发后的n秒后才执行，如果在等待的n秒内又被触发，则以最后一次的时间为准。一句话，等你触发完事件n秒内不再触发我才会去执行。

// // 根据特性写出第一版
// function debounce(fun, wait) {
//     let timer
//     return function() {
//         clearTimeout(timer)
//         timer = setTimeout(fun, wait)
//     }
// }
// // 测试一下
// document.onmousemove = debounce(userAction, 1000)
// 鼠标停止1秒后，数字加1，最基本的效果有了。

// 但是，正常写法的this是触发对象也就是document，以第一版的写法打印出来的确是window。
// function debounce(fun, wait) {
//     let timer
//     return function() {
//         let ctx = this  //当前this指向正确，为document
//         clearTimeout(timer)
//         timer = setTimeout(fun.bind(ctx), wait) //改变传入的fun的this指向
//     }
// }
// document.onmousemove = debounce(userAction, 1000)   // 当前已可保证this指向正确

// 还有一个问题就是事件对象没有传过来，只会打印undefined, 改进一下
// function debounce(fun, wait) {
//     let timer
//     return function() {
//         let ctx = this
//         let arg = arguments
//         clearTimeout(timer)
//         timer = setTimeout(() => {
//             fun.apply(ctx, arg)     // 改为apply，参数以数组的方式传递。
//         }, wait)
//     }
// }
// document.onmousemove = debounce(userAction, 1000)

// 上面代码已经很完善了，试想如果我不希望等待事件停止触发才执行函数,希望立即执行，然后等到停止触发n秒后，才可以重新触发执行。
// 通过传入一个可选参数immediate来控制是否立即执行
// function debounce(fun, wait, immediate) {
//     let timer
//     return function() {
//         let ctx = this
//         let arg = arguments
//         clearTimeout(timer)
//         if (immediate) {    //传入参数控制立即执行
//             if (!timer) {
//                 fun.apply(ctx, arg) //如果没有延时器运行，立即执行
//             }
//             timer = setTimeout(() => {  // 事件触发，设置延时器
//                 timer = undefined   // 停止触发wait毫秒后，清空timer，下次触发的时候就可以立即执行。
//             }, wait)
//         } else {    // 没有参数immediate或者传入false，保持原来的逻辑
//             timer = setTimeout(() => {
//                 fun.apply(ctx, arg)
//             }, wait)
//         }
//     }
// }
// document.onmousemove = debounce(userAction, 1000, true)

// 函数返回值还没有考虑到，因为延迟执行的话，返回值没办法立即获取到，就只在immediate为true时返回。
// function debounce(fun, wait, immediate) {
//     let timer
//     return function() {
//         let ctx = this
//         let arg = arguments
//         let res
//         clearTimeout(timer)
//         if (immediate) {
//             if (!timer) {
//                 res = fun.apply(ctx, arg)
//             }
//             timer = setTimeout(() => {
//                 timer = undefined
//             }, wait)
//         } else {
//             setTimeout(() => {
//                 fun.apply(ctx, arg)
//             }, wait)
//         }
//         return res
//     }
// }
// let debouncedFun = debounce(function (e) {
//     console.log(e)
//     console.log(this)
//     return 'hello debounce'
// }, 1000, true)  // 防抖处理过的函数
// document.onmousemove = function(e) {
//     let res = debouncedFun(e)
//     if (res) {  // 在等待阶段返回值是undefined，函数执行时有值。
//         console.log(res)
//     }
// }

//最后增加一个取消功能，用途：假如防抖延迟10秒，immediate为ture，这样只有等待10秒才能重新触发，现在有一个按钮，点击可以立即清空防抖延迟。
function debounce(fun, wait, immediate) {
    let timer
    let debouncedFun = function() {
        let arg = arguments
        let ctx = this
        let res
        clearTimeout(timer)
        if (immediate) {
            if (!timer) {
                res = fun.apply(ctx, arg)
            }
            timer = setTimeout(() => {
                timer = undefined
            }, wait)
        } else {
            timer = setTimeout(() => {
                fun.apply(ctx, arg)
            }, wait)
        }
        return res
    }
    debouncedFun.cancel = function(){
        clearTimeout(timer)
        timer = undefined
    }
    return debouncedFun
}
let debouncedFun = debounce(userAction, 10000, true)
document.onmousemove = debouncedFun
let button = document.createElement('button')
button.innerText = '点击清除防抖延时'
button.onclick = debouncedFun.cancel
document.body.appendChild(button)

// 大功告成，撒花🎉🎉